/*
 *    Copyright (c) 2018-2025, boss All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the boss developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: boss
 */
package com.hopes.bizz.risk.hid.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hopes.bizz.common.core.util.CollectionUtils;
import com.hopes.bizz.common.core.util.StringUtils;
import com.hopes.bizz.common.core.validate.ValidatorUtils;
import com.hopes.bizz.risk.common.constant.FlowConstant;
import com.hopes.bizz.risk.common.constant.HidDicConstant;
import com.hopes.bizz.risk.common.constant.enums.RiskSysDictEnum;
import com.hopes.bizz.risk.gis.constant.RiskStatisticsCycleEnum;
import com.hopes.bizz.risk.gis.helper.LineStatisticsHelper;
import com.hopes.bizz.risk.gis.vo.LineStatistics;
import com.hopes.bizz.risk.hid.bo.RiskHidHiddenDangerBO;
import com.hopes.bizz.risk.hid.bo.RiskHidTaskBo;
import com.hopes.bizz.risk.hid.dto.RiskHidHiddenDangerExcelDTO;
import com.hopes.bizz.risk.hid.dto.RiskHidStatisticsDTO;
import com.hopes.bizz.risk.hid.entity.RiskHidHandleRecordEntity;
import com.hopes.bizz.risk.hid.entity.RiskHidHiddenDangerDelayEntity;
import com.hopes.bizz.risk.hid.entity.RiskHidHiddenDangerEntity;
import com.hopes.bizz.risk.hid.mapper.RiskHidHiddenDangerMapper;
import com.hopes.bizz.risk.hid.service.RiskHidHandleRecordService;
import com.hopes.bizz.risk.hid.service.RiskHidHiddenDangerDelayService;
import com.hopes.bizz.risk.hid.service.RiskHidHiddenDangerService;
import com.hopes.bizz.risk.hid.vo.*;
import com.hopes.bizz.risk.parkgis.vo.OrgHidVO;
import com.hopes.bizz.risk.transfer.bean.entity.RiskTransferAuthEntity;
import com.hopes.bizz.risk.transfer.service.RiskTransferAuthService;
import com.hopes.boss.act.base.FlowServiceImpl;
import com.hopes.boss.act.enums.FlowTaskHandlerType;
import com.hopes.boss.act.vo.FlowTaskInfo;
import com.hopes.boss.admin.api.resolver.DictResolver;
import com.hopes.boss.admin.api.resolver.enums.AdminDictEnum;
import com.hopes.boss.common.entity.ValidateImportBO;
import com.hopes.boss.common.excel.vo.ErrorMessage;
import com.hopes.boss.common.security.util.SecurityUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 隐患信息
 *
 * @author pig
 * @date 2023-07-18 10:51:29
 */
@Service
public class RiskHidHiddenDangerServiceImpl extends FlowServiceImpl<RiskHidHiddenDangerMapper, RiskHidHiddenDangerEntity> implements RiskHidHiddenDangerService {

    @Resource
    private RiskHidHandleRecordService riskHidHandleRecordService;

    @Resource
    private RiskHidHiddenDangerDelayService riskHidHiddenDangerDelayService;

    @Resource
    private RiskTransferAuthService riskTransferAuthService;

    // 导入前执行
    @Override
    public void beforeImportExcel() {
        RiskHidHiddenDangerService.super.beforeImportExcel();
    }

    @Override
    public ValidateImportBO<RiskHidHiddenDangerExcelDTO> validateImport(List<RiskHidHiddenDangerExcelDTO> excelDTOList) {
        ValidateImportBO<RiskHidHiddenDangerExcelDTO> bo = new ValidateImportBO<>();
        List<ErrorMessage> errorMessageList = new ArrayList<>();
        List<RiskHidHiddenDangerExcelDTO> saveList = new ArrayList<>();
        int successNum = 0;
        int failedNum = 0;
        for (RiskHidHiddenDangerExcelDTO hidHiddenDangerExcelDTO : excelDTOList) {
            String validateRes = ValidatorUtils.validateEntity(hidHiddenDangerExcelDTO);
            if (StrUtil.isEmpty(validateRes)) {
                successNum++;
                saveList.add(hidHiddenDangerExcelDTO);
            } else {
                failedNum++;
                errorMessageList.add(new ErrorMessage(hidHiddenDangerExcelDTO.getLineNum(), new HashSet<String>() {{
                    add(validateRes);
                }}));
            }
        }
        bo.setErrorMessages(errorMessageList);
        bo.setSaveList(saveList);
        bo.setSuccessNum(successNum);
        bo.setFailedNum(failedNum);
        return bo;
    }

    @Override
    public RiskHidHiddenDangerEntity importDtoToEntity(RiskHidHiddenDangerExcelDTO excelDto) {
        RiskHidHiddenDangerEntity entity = new RiskHidHiddenDangerEntity();
        BeanUtils.copyProperties(excelDto, entity);
        entity.setHidLevel(Integer.valueOf(DictResolver.getItemValueByLabel(RiskSysDictEnum.danger_level, excelDto.getHidLevel())));
        entity.setHidSource(Integer.valueOf(DictResolver.getItemValueByLabel(RiskSysDictEnum.hidden_danger_check_type_and_source, excelDto.getHidSource())));
        entity.setHidType(Integer.valueOf(DictResolver.getItemValueByLabel(RiskSysDictEnum.danger_type, excelDto.getHidType())));
        entity.setDeptId(Long.valueOf(DictResolver.getItemValueByLabel(AdminDictEnum.sys_dept, excelDto.getDeptId())));
        // 延期状态
        entity.setDelayStatus(HidDicConstant.DELAY_STATUS_NORMAL);
        // 隐患审批状态
        entity.setAuditStatus(HidDicConstant.HIDDEN_DANGER_AUDIT_STATUS_NORMAL);
        // 隐患状态待提交
        entity.setHidStatus(HidDicConstant.HID_DANGER_STATUS_WAIT_SUBMIT);
        return entity;
    }

    @Override
    public RiskHidHiddenDangerExcelVO exportEntityToVo(RiskHidHiddenDangerEntity entity) {
        RiskHidHiddenDangerExcelVO excelVO = new RiskHidHiddenDangerExcelVO();
        BeanUtils.copyProperties(entity, excelVO);
        return excelVO;
    }

    @Override
    public RiskHidHiddenDangerEntity getOneByRiskHid(String code) {
        return this.baseMapper.getOneByRiskHid(code);
    }

    @Override
    public Map<Long, Long> countGroupByCompany() {
        return getBaseMapper().countGroupByCompany();
    }

    @Override
    public List<OrgHidVO> listGroupLevelCompany(Date startTime) {
        return getBaseMapper().listGroupLevelCompany(startTime);
    }

    @Override
    public RiskHidHiddenDangerEntity getByUid(String uid) {
        return baseMapper.getByUid(uid);
    }

    @Override
    public RiskHidCountStatistics calculateRiskHidCountStatistics(RiskHidStatisticsDTO riskHidStatisticsDTO) {
        RiskHidCountStatistics riskHidCountStatistics = new RiskHidCountStatistics();
        // 查询隐患
        List<Long> riskOrgIdList = getRiskOrgIdList(riskHidStatisticsDTO);
        List<RiskHidHiddenDangerEntity> hidList = getRiskHidList(riskHidStatisticsDTO, riskOrgIdList);
        Map<Integer, Long> countMap = hidList.stream().collect(Collectors.groupingBy(RiskHidHiddenDangerEntity::getHidLevel, Collectors.counting()));
        riskHidCountStatistics.setGeneralHidCount(Optional.ofNullable(countMap.get(HidDicConstant.DANGER_LEVEL_GENERAL)).map(Long::intValue).orElse(0));
        riskHidCountStatistics.setMajorHidCount(Optional.ofNullable(countMap.get(HidDicConstant.DANGER_LEVEL_MAJOR)).map(Long::intValue).orElse(0));
        riskHidCountStatistics.setTotalHidCount(hidList.size());
        return riskHidCountStatistics;
    }

    @Override
    public LineStatistics calculateRiskHidTrendStatistics(RiskHidStatisticsDTO riskHidStatisticsDTO) {
        List<Long> riskOrgIdList = getRiskOrgIdList(riskHidStatisticsDTO);
        List<RiskHidHiddenDangerEntity> hidList = getRiskHidList(riskHidStatisticsDTO, riskOrgIdList);
        Date beginTime = riskHidStatisticsDTO.getBeginTime();
        Date endTime = riskHidStatisticsDTO.getEndTime();

        LineStatisticsHelper<RiskHidHiddenDangerEntity> lineStatisticsHelper = new LineStatisticsHelper<>();
        lineStatisticsHelper.setBeginTime(beginTime);
        lineStatisticsHelper.setEndTime(endTime);
        lineStatisticsHelper.setGroupFun(t->DictResolver.getItemLabelByValue(AdminDictEnum.sys_company,t.getOrgId()));
        lineStatisticsHelper.setData(hidList);
        lineStatisticsHelper.setHandlerDateFun(RiskHidHiddenDangerEntity::getReportDate);
        lineStatisticsHelper.setLegendData(riskOrgIdList.stream().map(orgId->DictResolver.getItemLabelByValue(AdminDictEnum.sys_company,orgId)).collect(Collectors.toList()));
        RiskStatisticsCycleEnum dateCycle = riskHidStatisticsDTO.getDateCycle();
        lineStatisticsHelper.setStepFun(date -> DateUtil.offset(date, RiskStatisticsCycleEnum.getDateField(dateCycle), 1));
        lineStatisticsHelper.setXDataFun(date -> RiskStatisticsCycleEnum.getDateFormat(dateCycle, date));
        return lineStatisticsHelper.doStatistics();
    }

    @Override
    public RiskHidRankingStatistics calculateRiskHidRankingStatistics(RiskHidStatisticsDTO riskHidStatisticsDTO) {
        RiskHidRankingStatistics riskHidRankingStatistics = new RiskHidRankingStatistics();
        List<Long> riskOrgIdList = getRiskOrgIdList(riskHidStatisticsDTO);
        List<RiskHidHiddenDangerEntity> hidList = getRiskHidList(riskHidStatisticsDTO, riskOrgIdList);
        Map<Long, List<RiskHidHiddenDangerEntity>> orgHidMap = hidList.stream().collect(Collectors.groupingBy(RiskHidHiddenDangerEntity::getOrgId));
        orgHidMap.entrySet().stream().sorted((x, y) -> y.getValue().size() - x.getValue().size()).forEach(v -> {
            Long orgId = v.getKey();
            String orgName = DictResolver.getItemLabelByValue(AdminDictEnum.sys_company, orgId);
            riskHidRankingStatistics.addCompany(orgName);
            List<RiskHidHiddenDangerEntity> orgHidList = v.getValue();
            Map<Integer, Long> orgHidLevelMap = orgHidList.stream().collect(Collectors.groupingBy(RiskHidHiddenDangerEntity::getHidLevel, Collectors.counting()));
            riskHidRankingStatistics.addGeneralHidCount(Optional.ofNullable(orgHidLevelMap.get(HidDicConstant.DANGER_LEVEL_GENERAL)).map(Long::intValue).orElse(0));
            riskHidRankingStatistics.addMajorHidCount(Optional.ofNullable(orgHidLevelMap.get(HidDicConstant.DANGER_LEVEL_MAJOR)).map(Long::intValue).orElse(0));
        });
        return riskHidRankingStatistics;
    }

    private List<RiskHidHiddenDangerEntity> getRiskHidList(RiskHidStatisticsDTO riskHidStatisticsDTO, List<Long> riskOrgIdList) {
        Integer hidSource = riskHidStatisticsDTO.getHidSource();
        Date beginTime = riskHidStatisticsDTO.getBeginTime();
        Date endTime = riskHidStatisticsDTO.getEndTime();
        List<RiskHidHiddenDangerEntity> hidList = lambdaQuery()
                .in(RiskHidHiddenDangerEntity::getOrgId, riskOrgIdList)
                .eq(Objects.nonNull(hidSource), RiskHidHiddenDangerEntity::getHidSource, hidSource)
                .ge(RiskHidHiddenDangerEntity::getReportDate, beginTime)
                .le(RiskHidHiddenDangerEntity::getReportDate, endTime)
                .select(RiskHidHiddenDangerEntity::getHidSource, RiskHidHiddenDangerEntity::getId, RiskHidHiddenDangerEntity::getHidLevel, RiskHidHiddenDangerEntity::getOrgId, RiskHidHiddenDangerEntity::getReportDate)
                .list();
        return hidList;
    }

    @NotNull
    private List<Long> getRiskOrgIdList(RiskHidStatisticsDTO riskHidStatisticsDTO) {
        List<Long> orgIdList = riskHidStatisticsDTO.getOrgId();
        if (CollectionUtils.isEmpty(orgIdList)) {
            orgIdList = riskTransferAuthService.lambdaQuery()
                    .eq(RiskTransferAuthEntity::getUse, Boolean.TRUE)
                    .select(RiskTransferAuthEntity::getOrgId)
                    .list().stream().map(RiskTransferAuthEntity::getOrgId).collect(Collectors.toList());
        }
        return orgIdList;
    }


    @Override
    public List<Integer> getSafetyHidData(RiskHidHiddenDangerBO danger) {
        return this.baseMapper.getSafetyHidData(danger);
    }

    @Override
    public void doCompletedTask(FlowTaskInfo flowTaskInfo, Long id, FlowTaskHandlerType handlerType, Object data) {

    }

    @Override
    public String getFlowDefinitionKey(Long id) {
        return FlowConstant.HIDDEN_DANGER;
    }


    @Override
    public void deleteBusiness(Collection<Long> hidList) {
        List<RiskHidHandleRecordEntity> list = riskHidHandleRecordService.lambdaQuery()
                .select(RiskHidHandleRecordEntity::getId)
                .in(RiskHidHandleRecordEntity::getHidId, hidList)
                .list();
        List<Long> idList = list.stream().map(RiskHidHandleRecordEntity::getId).collect(Collectors.toList());
        riskHidHandleRecordService.removeBatchByIds(idList);
        //删除相关的延期申请
        riskHidHiddenDangerDelayService.remove(Wrappers.lambdaQuery(RiskHidHiddenDangerDelayEntity.class).in(RiskHidHiddenDangerDelayEntity::getHiddenDangerId, hidList));
    }

    private String getHidCode() {
        RiskHidHiddenDangerEntity lastHid = lambdaQuery().orderByDesc(RiskHidHiddenDangerEntity::getCreateTime).last("limit 1")
                .select(RiskHidHiddenDangerEntity::getHidCode).one();
        int index = 1;
        if (Objects.nonNull(lastHid)) {
            String hidCode = lastHid.getHidCode();
            index += Integer.parseInt(hidCode.substring(hidCode.lastIndexOf("_") + 1));
        }

        return HidDicConstant.HID_CODE_NAME + "_" + DateUtil.format(new Date(), "yyyyMMddHHmmss") + "_" + index;
    }

    @Override
    public String setSearchKeyword(Long id) {
        RiskHidHiddenDangerEntity riskHidHiddenDanger = getById(id);
        if (ObjectUtil.isNotEmpty(riskHidHiddenDanger)) {
            return riskHidHiddenDanger.getHidCode();
        }
        return null;
    }
}
